import csv
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
from cpmm import CPMM, run_experiment
Slippage is an inefficiency of CPMM that results in slightly (or significantly) worse odds when betting. For example in perfect market with outcome probabilities split equally, if you stake \$100 for "yes" and "yes" wins then you receive \$200 (\$100 stake + \$100 profit). In case of CPMM with \$1000 liquidity you will receive ~\$191 payout and you lose \$9 to the market inefficiency. In other words your odds are not 1:1 but ~0.91:1. This difference of \$9 is called slippage.
In our simulations we define slippage as a fraction of reward lost slippage = (actual token price - marginal token price) / actual token price
So for example slippage 0.03 (3%) means reduction of possible reward by 3% due to inefficient market.
Slippage has negative effect on trading.
Slippage is function of bet amount / liquidity amount. For example we have the same slippage for bet amount 100 with liquidity amount 1000 and bet amount 1000 with liquidity 10000.
Example above assumes 1:1 yes:no odds
cpmm = CPMM()
initial_liquidity = 1000
cpmm.create_event(initial_liquidity)
# slippage vs increased bets
slippages = [[amount / initial_liquidity , cpmm.calc_slippage(0, amount)] for amount in range(1, 3000, 5)]
df = pd.DataFrame(data=slippages, columns=["bet amount/liquidity", "slippage"])
# layout = px.Layout(yaxis=dict(tickformat=".2%"))
fig = px.line(df, x="bet amount/liquidity", y="slippage", title='Slippage vs bet amount as % of liquidity')
fig.show()
We have 1% of slippage when bet is 2% of liquidity and 2% of slippage when bet is 4.18% of liquidity. If we assume that 1% of slippage is realistic maximum we need \$1000 liquidity to have \$20 bets or \$50,000 liquidity to have \$1000 bets. With 1% slippage trader loses \$10 out of \$1000 bet
# slippage vs increased bets
cpmm = CPMM()
initial_liquidity = 1000
cpmm.create_event(initial_liquidity)
zoom = 20.0
slippages = [[(amount / zoom) / initial_liquidity , cpmm.calc_slippage(0, amount / zoom)] for amount in range(1, 1000, 5)]
df = pd.DataFrame(data=slippages, columns=["bet amount/liquidity", "slippage"])
fig = px.line(df, x="bet amount/liquidity", y="slippage", title='Slippage vs bet amount as % of liquidity')
fig.show()
With odds 1:1 we have 0.5% slippage for both outcomes, with yes:no odds 1:8 we have 2.5% slippage for NO which is quite large (and very small slippage for YES). However NO option is much more interesting to gamblers as possible payout is higher!
In scenario below we start at 1:1 odds and traders bet on YES decreasing the YES odds and increasing the NO odds. Observe slippage value changing!
from IPython.display import Markdown, display
cpmm = CPMM()
initial_liquidity = 1000
amount = 10
cpmm.create_event(initial_liquidity)
slippages = []
odds_yes = 1
odds_no = 1
for i in range(0, 200):
# (initial_liquidity + amount*i) / initial_liquidity
slippages.append([odds_yes, odds_no, cpmm.calc_slippage(1, amount), cpmm.calc_slippage(0, amount)])
yes_payout = cpmm.buy_token(1, amount)[1]
no_payout = cpmm.calc_buy(0, amount)[0]
odds_yes = cpmm.calc_british_odds(yes_payout, amount)
odds_no = cpmm.calc_british_odds(no_payout, amount)
df = pd.DataFrame(data=slippages, columns=["odds yes", "odds no", "slippage yes", "slippage no"])
fig = px.line(df, x="odds yes", y=["slippage yes", "slippage no"], title='slippage vs yes odds')
fig.update_xaxes(autorange="reversed", ticksuffix=":1")
display(fig.show())
fig = px.line(df, x="odds no", y=["slippage yes", "slippage no"], title='slippage vs no odds')
fig.update_xaxes(ticksuffix=":1")
display(fig.show())
display(df)
None
None
| odds yes | odds no | slippage yes | slippage no | |
|---|---|---|---|---|
| 0 | 1.000000 | 1.000000 | 0.004950 | 0.004950 |
| 1 | 0.990099 | 1.009900 | 0.004853 | 0.005049 |
| 2 | 0.970685 | 1.029895 | 0.004758 | 0.005148 |
| 3 | 0.951837 | 1.050084 | 0.004666 | 0.005248 |
| 4 | 0.933532 | 1.070467 | 0.004575 | 0.005348 |
| ... | ... | ... | ... | ... |
| 195 | 0.115300 | 8.453133 | 0.000348 | 0.025701 |
| 196 | 0.114521 | 8.509713 | 0.000345 | 0.025804 |
| 197 | 0.113750 | 8.566476 | 0.000342 | 0.025906 |
| 198 | 0.112987 | 8.623422 | 0.000338 | 0.026009 |
| 199 | 0.112231 | 8.680552 | 0.000335 | 0.026111 |
200 rows × 4 columns
Slippage will be acceptable for betters only in certain bet sizes (as fraction of liquidity) and odds. For high odds slippage is quickly becoming considerable. Two results
slippage_mx = []
initial_liquidity = 1000
# for a range of initial splits
y_to_n = 0.2
while y_to_n < 8:
cpmm = CPMM()
cpmm.create_event(initial_liquidity, initial_yes_to_no=y_to_n)
for amount in range(5, initial_liquidity // 2, 10):
yes_payout = cpmm.calc_buy(1, amount)[0]
slippage = cpmm.calc_slippage(1, amount)
slippage_mx.append([amount, cpmm.calc_british_odds(yes_payout, amount), slippage])
y_to_n = y_to_n*1.1
df = pd.DataFrame(data=slippage_mx, columns=["amount", "odds", "slippage"])
color_continuous_scale = ["green", "white", "red"]
fig = px.scatter(df,
title=f"Slippage vs odds vs amount",
labels=dict(x="Bet amount as fraction of liquidity", y="Odds of bought option", color="Slippage %"),
color_continuous_midpoint=5,
range_color=[0, 10],
color_continuous_scale=color_continuous_scale,
x=df["amount"] / initial_liquidity,
y="odds",
color=df["slippage"]*100)
fig.update_yaxes(ticksuffix=":1")
fig.show()
df_small_odds = df[df["odds"] < 1]
fig = px.scatter(df_small_odds,
title=f"Slippage vs odds vs amount",
labels=dict(x="Bet amount as fraction of liquidity", y="Odds of bought option", color="Slippage %"),
color_continuous_midpoint=5,
range_color=[0, 10],
color_continuous_scale=color_continuous_scale,
x=df_small_odds["amount"] / initial_liquidity,
y=df["odds"],
color=df_small_odds["slippage"]*100)
fig.update_yaxes(ticksuffix=":1")
fig.show()